'''
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with self work for additional information
 * regarding copyright ownership.  The ASF licenses self file
 * to you under the Apache License, Version 2.0 (the
 * "License") you may not use self file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http:#www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
'''
from base.java.System import System
from base.util.iterator.impl.IteratorImpl import IteratorImpl

#import org.apache.jena.graph.Triple
#import org.apache.jena.mem2.spliterator.ArraySpliterator
#import org.apache.jena.util.iterator.ExtendedIterator
#import org.apache.jena.util.iterator.NiceIterator

#import java.util.ConcurrentModificationException
#import java.util.NoSuchElementException
#import java.util.Spliterator
#import java.util.function.Consumer
#import java.util.function.Predicate

'''
 * An ArrayBunch implements TripleBunch with a linear search of a short-ish
 * array of Triples. The array grows by factor 2.
'''
from abc import ABC, abstractmethod
# private static final int
INITIAL_SIZE = 4


class FastArrayBunch(ABC):



    # protected int size = 0
    # protected Triple[] elements

    # param 
    # result protected
    def __init__(self):
        self.size = 0
        # Triple
        self.elements = [None for _ in range(INITIAL_SIZE)]
    

    # param final Triple a, final Triple b
    # result abstract boolean
    @abstractmethod
    def areEqual(self, a, b):
        pass

    ##@Override
    # param Triple t
    # result boolean
    def containsKey(self, t):
        # int
        i = self.size
        while i > 0:
            i = i - 1
            if self.areEqual(t, self.elements[i]):
                return True
        return False

    ##@Override
    # param final Predicate<Triple> predicate
    # result boolean
    def anyMatch(self, predicate):
        i = self.size
        while i > 0:
            i = i - 1
            if predicate.test(self.elements[i]):
                return True
        return False
    

    ##@Override
    # param Predicate<Triple> predicate
    # result boolean
    def anyMatchRandomOrder(self, predicate):
        return self.anyMatch(predicate)
    

    ##@Override
    # param 
    # result void
    def clear(self):
        # Triple
        self.elements = [None for _ in range(INITIAL_SIZE)]
        self.size = 0
    

    ##@Override
    # param 
    # result int
    def size(self):
        return self.size
    

    ##@Override
    # param 
    # result boolean
    def isEmpty(self):
        return self.size == 0
    

    ##@Override
    # param final Triple t
    # result boolean
    def tryAdd(self, t):
        if self.containsKey(self):
            return False
        if self.size == len(self.elements):
            self.grow()
        self.elements[self.size] = t
        self.size += 1
        return True
    

    ##@Override
    # param final Triple t
    # result void
    def addUnchecked(self, t):
        if self.size == len(self.elements):
            self.grow()
        self.elements[self.size] = t
        self.size += 1

    '''
     * Note: linear growth is suboptimal (order n<sup>2</sup>) normally, but
     * ArrayBunch's are meant for <i>small</i> sets and are replaced by some
     * sort of hash- or tree- set when they get big currently "big" means more
     * than 9 elements, so that's only one growth spurt anyway.
    '''
    # param 
    # result void
    def grow(self):
        # final var
        oldElements = self.elements
        # Triple
        elements = [None for _ in range(self.size << 1)]
        System.arraycopy(oldElements, 0, elements, 0, self.size)
    

    #@Override
    # param final Triple
    # result boolean
    def tryRemove(self, t):
        for i in range(self.size):
            if (self.areEqual(t, self.elements[i])):
                self.size -= 1
                self.elements[i] = self.elements[self.size]
                return True
        return False

    #@Override
    # param final Triple
    # result void
    def removeUnchecked(self, t):
        for i in range(self.size):
            if (self.areEqual(t, self.elements[i])):
                self.size -= 1
                self.elements[i] = self.elements[self.size]
                return

    def keyIterator(self):
        return IteratorImpl(self.elements)

    '''
     #@Override
    public ExtendedIterator<Triple> keyIterator():
        return new NiceIterator<>():
            private final int initialSize = size

            private int i = size

             #@Override
            # result boolean
            def hasNext():
                return 0 < i
            }

             #@Override
            public Triple next():
                if (size != initialSize) throw new ConcurrentModificationException()
                if (i == 0) throw new NoSuchElementException()
                return elements[--i]
            }

             #@Override
            public void forEachRemaining(Consumer<? super Triple> action):
                while (0 < i--) action.accept(elements[i])
                if (size != initialSize) throw new ConcurrentModificationException()
            }
        }



     #@Override
    public Spliterator<Triple> keySpliterator():
        final var initialSize = size
        final Runnable checkForConcurrentModification = () -> {
            if (size != initialSize) throw new ConcurrentModificationException()
        }
        return new ArraySpliterator<>(elements, size, checkForConcurrentModification)
    '''

    #@Override
    # param
    # result boolean
    def isArray(self):
        return True

    #@Override
    # param Triple key, int hashCode
    # result boolean
    def tryAddWithHashCode(self, key, hashCode):
        return self.tryAdd(key)

    #@Override
    # param Triple key, int hashCode
    # result void
    def addUncheckedWithHashCode(self, key, hashCode):
        self.addUnchecked(key)

    #@Override
    # param Triple key, int hashCode
    # result boolean
    def tryRemoveWithHashCode(self, key, hashCode):
        return self.tryRemove(key)

    #@Override
    # param Triple key, int hashCode
    # result void
    def removeUncheckedWithHashCode(self, key, hashCode):
        self.removeUnchecked(key)
    

